package common

import (
	"fmt"
	"log"
	"reflect"
	"strings"

	"github.com/shopspring/decimal"
)

// PrecisionDetector 精度检测器
type PrecisionDetector struct {
	Issues []PrecisionIssue
}

// PrecisionIssue 精度问题
type PrecisionIssue struct {
	File        string `json:"file"`
	Line        int    `json:"line"`
	Type        string `json:"type"`
	Description string `json:"description"`
	Severity    string `json:"severity"`
	Fix         string `json:"fix"`
}

// NewPrecisionDetector 创建精度检测器
func NewPrecisionDetector() *PrecisionDetector {
	return &PrecisionDetector{
		Issues: make([]PrecisionIssue, 0),
	}
}

// DetectInexactFloat64Usage 检测 InexactFloat64 使用
func (d *PrecisionDetector) DetectInexactFloat64Usage(code string, filePath string) {
	lines := strings.Split(code, "\n")
	for i, line := range lines {
		if strings.Contains(line, "InexactFloat64()") {
			d.Issues = append(d.Issues, PrecisionIssue{
				File:        filePath,
				Line:        i + 1,
				Type:        "InexactFloat64",
				Description: "使用 InexactFloat64() 可能导致精度损失",
				Severity:    "HIGH",
				Fix:         "使用 FormatDecimal() 或 String() 方法保持精度",
			})
		}
	}
}

// DetectFloat64Conversion 检测 float64 转换
func (d *PrecisionDetector) DetectFloat64Conversion(code string, filePath string) {
	lines := strings.Split(code, "\n")
	for i, line := range lines {
		if strings.Contains(line, ".Float64()") {
			d.Issues = append(d.Issues, PrecisionIssue{
				File:        filePath,
				Line:        i + 1,
				Type:        "Float64",
				Description: "使用 Float64() 可能导致精度损失",
				Severity:    "MEDIUM",
				Fix:         "使用 FormatDecimal() 或 String() 方法保持精度",
			})
		}
	}
}

// DetectFloat64AmountFields 检测使用 float64 的金额字段
func (d *PrecisionDetector) DetectFloat64AmountFields(code string, filePath string) {
	lines := strings.Split(code, "\n")
	for i, line := range lines {
		if strings.Contains(line, "float64") &&
			(strings.Contains(line, "Amount") ||
				strings.Contains(line, "Balance") ||
				strings.Contains(line, "Fee") ||
				strings.Contains(line, "Total")) {
			d.Issues = append(d.Issues, PrecisionIssue{
				File:        filePath,
				Line:        i + 1,
				Type:        "Float64Amount",
				Description: "金额字段使用 float64 类型，可能导致精度损失",
				Severity:    "HIGH",
				Fix:         "将字段类型改为 decimal.Decimal",
			})
		}
	}
}

// ValidateDecimalPrecision 验证 decimal 精度
func (d *PrecisionDetector) ValidateDecimalPrecision(amount decimal.Decimal, expectedPrecision int32) error {
	actualPrecision := -amount.Exponent()
	if actualPrecision > expectedPrecision {
		return fmt.Errorf("精度超出预期: 实际精度=%d, 预期精度=%d", actualPrecision, expectedPrecision)
	}
	return nil
}

// TestPrecisionLoss 测试精度损失
func (d *PrecisionDetector) TestPrecisionLoss() {
	log.Println("🔍 开始精度损失测试...")

	// 测试用例1: 0.1 + 0.2
	a := decimal.NewFromFloat(0.1)
	b := decimal.NewFromFloat(0.2)
	result := a.Add(b)
	expected, _ := decimal.NewFromString("0.30")

	if !result.Equal(expected) {
		log.Printf("❌ 精度损失测试失败: 0.1 + 0.2 = %s, 期望: %s", result, expected)
	} else {
		log.Printf("✅ 精度测试通过: 0.1 + 0.2 = %s", result)
	}

	// 测试用例2: 大数计算
	largeAmount, _ := decimal.NewFromString("123456789.123456789")
	smallAmount, _ := decimal.NewFromString("0.000000001")
	sum := largeAmount.Add(smallAmount)

	if !sum.Equal(largeAmount.Add(smallAmount)) {
		log.Printf("❌ 大数精度测试失败: %s + %s = %s", largeAmount, smallAmount, sum)
	} else {
		log.Printf("✅ 大数精度测试通过: %s + %s = %s", largeAmount, smallAmount, sum)
	}

	// 测试用例3: 格式化精度
	amount, _ := decimal.NewFromString("123.456789")
	formatted := FormatDecimal(amount)
	expectedFormatted := "123.46"

	if formatted != expectedFormatted {
		log.Printf("❌ 格式化精度测试失败: %s, 期望: %s", formatted, expectedFormatted)
	} else {
		log.Printf("✅ 格式化精度测试通过: %s", formatted)
	}
}

// GenerateReport 生成检测报告
func (d *PrecisionDetector) GenerateReport() string {
	if len(d.Issues) == 0 {
		return "✅ 未发现精度问题"
	}

	report := "🔍 精度问题检测报告\n"
	report += fmt.Sprintf("发现 %d 个问题:\n\n", len(d.Issues))

	highCount := 0
	mediumCount := 0
	lowCount := 0

	for _, issue := range d.Issues {
		report += fmt.Sprintf("📍 %s:%d - %s (%s)\n", issue.File, issue.Line, issue.Description, issue.Severity)
		report += fmt.Sprintf("   修复建议: %s\n\n", issue.Fix)

		switch issue.Severity {
		case "HIGH":
			highCount++
		case "MEDIUM":
			mediumCount++
		case "LOW":
			lowCount++
		}
	}

	report += fmt.Sprintf("📊 统计:\n")
	report += fmt.Sprintf("   🔴 高严重性: %d\n", highCount)
	report += fmt.Sprintf("   🟡 中严重性: %d\n", mediumCount)
	report += fmt.Sprintf("   🟢 低严重性: %d\n", lowCount)

	return report
}

// CheckStructFields 检查结构体字段的精度问题
func (d *PrecisionDetector) CheckStructFields(structType reflect.Type, filePath string) {
	for i := 0; i < structType.NumField(); i++ {
		field := structType.Field(i)

		// 检查字段类型
		if field.Type.Kind() == reflect.Float64 {
			// 检查字段名是否包含金额相关词汇
			fieldName := strings.ToLower(field.Name)
			if strings.Contains(fieldName, "amount") ||
				strings.Contains(fieldName, "balance") ||
				strings.Contains(fieldName, "fee") ||
				strings.Contains(fieldName, "total") ||
				strings.Contains(fieldName, "price") ||
				strings.Contains(fieldName, "cost") {

				d.Issues = append(d.Issues, PrecisionIssue{
					File:        filePath,
					Line:        0, // 无法确定具体行号
					Type:        "Float64Field",
					Description: fmt.Sprintf("结构体字段 %s 使用 float64 类型", field.Name),
					Severity:    "HIGH",
					Fix:         fmt.Sprintf("将字段 %s 类型改为 decimal.Decimal", field.Name),
				})
			}
		}
	}
}

// ValidateAmountString 验证金额字符串格式
func (d *PrecisionDetector) ValidateAmountString(amountStr string) error {
	// 检查是否为空
	if strings.TrimSpace(amountStr) == "" {
		return fmt.Errorf("金额字符串不能为空")
	}

	// 检查格式
	amount, err := decimal.NewFromString(amountStr)
	if err != nil {
		return fmt.Errorf("无效的金额格式: %s", amountStr)
	}

	// 检查是否为负数
	if amount.IsNegative() {
		return fmt.Errorf("金额不能为负数: %s", amountStr)
	}

	// 检查精度
	if amount.Exponent() < -8 {
		return fmt.Errorf("金额精度过高: %s", amountStr)
	}

	return nil
}

// ComparePrecision 比较两个金额的精度
func (d *PrecisionDetector) ComparePrecision(a, b decimal.Decimal) (int32, int32) {
	return -a.Exponent(), -b.Exponent()
}

// LogPrecisionInfo 记录精度信息
func (d *PrecisionDetector) LogPrecisionInfo(amount decimal.Decimal, context string) {
	log.Printf("🔢 精度信息 [%s]: 值=%s, 精度=%d",
		context, amount.String(), -amount.Exponent())
}
